#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/12/9 10:51
# @Author  : LiShan
# @Email   : lishan_1997@126.com
# @File    : main.py
# @Note    : this is note

import os
import sys

import PySide2
import cv2.cv2 as cv
from PySide2 import QtWidgets
from PySide2.QtCore import QDir, QTimer
from PySide2.QtGui import QPixmap, QImage, QIcon
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QMainWindow, QFileDialog, QMessageBox

from ui.ui_mainwindow import Ui_MainWindow
# from traffic_flow import TrafficFlowDetected

dirname = os.path.dirname(PySide2.__file__)
plugin_path = os.path.join(dirname, 'plugins', 'platforms')
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path


# 登录界面
class LogIn:
    def __init__(self):
        """
        功能：初始化登录界面
        """
        self.ui = QUiLoader().load("./ui/login.ui")
        self.ui.setWindowIcon(QIcon("./icon/icon.png"))
        self.ui.setFixedSize(self.ui.width(), self.ui.height())
        self.user = "root"
        self.password = "123456"
        self.ui.btnLogin.clicked.connect(self.btnlogin_clicked)

    def btnlogin_clicked(self):
        """
       功能：验证登录信息
       """
        verify_result = self.ui.txtUserID.text() == self.user and self.ui.txtPWD.text() == self.password
        if verify_result:
            QMessageBox.about(self.ui,
                              '登录提示',
                              '登录成功'
                              )
            self.ui.hide()
            window.ui.show()

        else:
            QMessageBox.about(self.ui,
                              '登录提示',
                              '登录失败'
                              )


# 主窗体类
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = QUiLoader().load("./ui/mainwindow.ui")
        self.ui.setWindowIcon(QIcon("./icon/icon.png"))
        self.ui.setFixedSize(self.ui.width(), self.ui.height())

        # 打开文件类型，用于类的定义
        self.f_type = 0
        # 定义控件属性
        self.ui.pushButton_switch.setEnabled(False)
        self.ui.pushButton_back.setEnabled(False)
        self.ui.pushButton_front.setEnabled(False)

        # 添加槽连接
        # self.ui.actionimage.triggered.connect(ImgConfig_init)
        self.ui.actionvideo.triggered.connect(VdoConfig_init)


# 定义视频类
class VdoConfig:
    def __init__(self):
        self.file = self.open_video()
        window.ui.pushButton_switch.setEnabled(False)
        window.ui.pushButton_back.setEnabled(False)
        window.ui.pushButton_front.setEnabled(False)
        # 背景差分法（混合高斯建模）创建一个对象
        self.bs = cv.createBackgroundSubtractorMOG2(detectShadows=False)
        if not self.file:
            return
        window.ui.label_hint.setText("正在读取请稍后...")

        # 设置时钟
        self.v_timer = QTimer()
        # 读取视频
        self.cap = cv.VideoCapture(self.file)
        # self.cap.set(3, 480)  # 设置分辨率，宽480，高320
        # self.cap.set(4, 320)
        if not self.cap:
            print("打开视频失败")
            return
        # 获取视频FPS
        self.fps = self.cap.get(cv.CAP_PROP_FPS)
        # 获取视频总帧数
        self.total_f = self.cap.get(cv.CAP_PROP_FRAME_COUNT)
        # 获取视频当前帧所在的帧数
        self.current_f = self.cap.get(cv.CAP_PROP_POS_FRAMES)
        # 设置定时器周期，单位毫秒
        self.v_timer.start(int(1000 / self.fps))
        print("FPS:{:.0f}".format(self.fps))

        window.ui.pushButton_switch.setEnabled(True)
        window.ui.pushButton_back.setEnabled(True)
        window.ui.pushButton_front.setEnabled(True)

        # 连接定时器周期溢出的槽函数，用于显示一帧视频
        self.v_timer.timeout.connect(self.show_pic)
        # 连接按钮和对应槽函数，lambda表达式用于传参
        window.ui.pushButton_switch.clicked.connect(self.go_pause)
        window.ui.pushButton_back.pressed.connect(lambda: self.last_img(True))
        window.ui.pushButton_back.clicked.connect(lambda: self.last_img(False))
        window.ui.pushButton_front.pressed.connect(lambda: self.next_img(True))
        window.ui.pushButton_front.clicked.connect(lambda: self.next_img(False))
        print("初始化设置成功")

    def show_pic(self):
        # 读取一帧
        success, frame = self.cap.read()
        if success:
            # 交通参数提取：车流量
            count = 0
            # 转灰度图
            gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
            # 计算高、宽
            height, width = gray.shape[0], gray.shape[1]
            # 提取前景腌膜
            fgmask = self.bs.apply(gray)
            # 中值滤波
            median = cv.medianBlur(fgmask, 5)
            # 形态学处理
            element = cv.getStructuringElement(cv.MORPH_RECT, (1, 1))
            element2 = cv.getStructuringElement(cv.MORPH_RECT, (1, 1))
            # 开运算
            image = cv.morphologyEx(median, cv.MORPH_OPEN, element)
            # 膨胀运算
            morphology = cv.dilate(image, element2)
            # 二值图像提取轮廓，轮廓跟踪算法（Suzuki，1985）
            contours, hierarchy = cv.findContours(morphology, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
            for cnt in contours:
                # 依次取出每一条轮廓，计算点集或灰度图像的非零像素的右上边界矩形
                x, y, w, h = cv.boundingRect(cnt)
                if y + h == 600:
                    count += 1
                # 过滤掉小物体
                if cv.contourArea(cnt) < width * height * 0.0005 or w < width * 0.01 or h < height * 0.01:
                    continue
                cv.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 3)
            frame = cv.resize(frame, (480, 320))
            # Mat格式图像转Qt中图像的方法
            show = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
            show_image = QImage(show.data,
                                show.shape[1],
                                show.shape[0],
                                QImage.Format_RGB888
                                )
            window.ui.label_hint.setPixmap(QPixmap.fromImage(show_image))

            # 状态栏显示信息
            self.current_f = self.cap.get(cv.CAP_PROP_POS_FRAMES)
            current_t, total_t = self.calculate_time(self.current_f,
                                                     self.total_f,
                                                     self.fps
                                                     )
            window.ui.statusbar.showMessage("文件名：{}  {}({})".format(self.file, current_t, total_t))

    def show_pic_back(self):
        # 获取视频当前帧所在的帧数
        self.current_f = self.cap.get(cv.CAP_PROP_POS_FRAMES)
        # 设置下一次帧为当前帧-2
        self.cap.set(cv.CAP_PROP_POS_FRAMES, self.current_f - 2)
        # 读取一帧
        success, frame = self.cap.read()
        if success:
            show = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
            show_image = QImage(show.data, show.shape[1], show.shape[0], QImage.Format_RGB888)
            window.ui.label_hint.setPixmap(QPixmap.fromImage(show_image))

            # 状态栏显示信息
            current_t, total_t = self.calculate_time(self.current_f - 1, self.total_f, self.fps)
            window.ui.statusbar.showMessage("文件名：{}        {}({})".format(self.file, current_t, total_t))

    # 快退
    def last_img(self, t):
        window.ui.pushButton_switch.setText("播放")
        if t:
            # 断开槽连接
            self.v_timer.timeout.disconnect(self.show_pic)
            # 连接槽连接
            self.v_timer.timeout.connect(self.show_pic_back)
            self.v_timer.start(int((1000 / self.fps) / 2))
        else:
            self.v_timer.timeout.disconnect(self.show_pic_back)
            self.v_timer.timeout.connect(self.show_pic)
            self.v_timer.start(int(1000 / self.fps))

    # 快进
    def next_img(self, t):
        window.ui.pushButton_switch.setText("播放")
        if t:
            self.v_timer.start(int((1000 / self.fps) / 2))
        else:
            self.v_timer.start(int(1000 / self.fps))

    # 暂停播放
    def go_pause(self):
        if window.ui.pushButton_switch.text() == "播放":
            self.v_timer.stop()
            window.ui.pushButton_switch.setText("暂停")
        elif window.ui.pushButton_switch.text() == "暂停":
            self.v_timer.start(int(1000 / self.fps))
            window.ui.pushButton_switch.setText("播放")

    @staticmethod
    def calculate_time(c_f, t_f, fps):
        total_seconds = int(t_f / fps)
        current_sec = int(c_f / fps)
        c_time = "{}:{}:{}".format(int(current_sec / 3600), int((current_sec % 3600) / 60), int(current_sec % 60))
        t_time = "{}:{}:{}".format(int(total_seconds / 3600), int((total_seconds % 3600) / 60), int(total_seconds % 60))
        return c_time, t_time

    @staticmethod
    # 打开视频
    def open_video():
        # 打开文件对话框
        file_dir, _ = QFileDialog.getOpenFileName(window.ui.pushButton_switch,
                                                  "打开视频",
                                                  QDir.currentPath(),
                                                  "视频文件(*.mp4 *.avi );;所有文件(*)"
                                                  )
        # 判断是否正确打开文件
        if not file_dir:
            QMessageBox.warning(window.ui.pushButton_switch,
                                "警告",
                                "文件错误或打开文件失败！",
                                QMessageBox.Yes
                                )
            return
        print("读入文件成功")
        # 返回视频路径
        return file_dir


def VdoConfig_init():
    window.f_type = VdoConfig()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    login_win = LogIn()
    login_win.ui.show()
    window.ui.hide()
    sys.exit(app.exec_())
